package middle;
/**
 * 5. 最长回文子串
 * 给定一个字符串 s，找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
 * 输入: "babad"
 * 输出: "bab"
 * 注意: "aba" 也是一个有效答案。
 * */
public class LongestPalindrome {
    // 暴力匹配(Brute Force) 时间复杂度：O(n^3) 空间复杂度： O(n)
    public String getLongestPalindrome(String s){
        int len = s.length();
        int maxLen = 1; // 匹配到最长回文子串的长度
        int begin = 0;
        char[] charArray = s.toCharArray();
        if(len < 2){
            return s;
        }
        // 枚举所有长度大于1的字符串
        for (int i = 0; i < s.length()-1; i++) {
            for (int j = i + 1; j < s.length(); j++){
                // 当匹配字符串长度低于上次最大长度时，不进行校验
                if(j - i + 1 > maxLen && validPalindromic(charArray, i, j)){
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);

    }

    // 验证是否为回文数
    public boolean validPalindromic(char[] charArray, int left, int right){
        while(left < right){
            if (charArray[left] != charArray[right]){
                return false;
            }
            left++;
            right--;
        }
        return true;
    }


    // 动态规划 时间复杂度:O(n^2)  空间复杂度： O(n^2)
    public String getLongestPalindrome1(String s){
        int i = 0, j = 0;
        int len = s.length();
        int begin = 0;
        int maxLen = 1;
        if(len < 2) {
            return s;
        }

        // dp[i][j] 表示字符串s从i开始到j终止的子串为回文串 此处是闭区间
        boolean[][] dp = new boolean[len][len];
        // 将字符串s 转换为字符串数组方便操作
        char[] chars = s.toCharArray();

        // 将字符串长度为1的所有状态值设置为true 完全不用写 填表流程
//        for (i = 0; i < len; i++) {
//            dp[i][i] = true;
//        }

        for (j = 1; j < len; j++) {
            for (i = 0; i < j; i++) {
                // 如果头尾不相同 则不为回文串
                if(chars[i] != chars[j]){
                    dp[i][j] = false;
                }else{
                    // 如果首尾相同 我们要判断字符串长度是否小于4,小于4自然就是回文串
                    if(j - i + 1 < 3){
                        dp[i][j] = true;
                    }else{
                        // 如果长度大于等于4 且首尾相同 则判断他的子串是否为回文串
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }
                // 只有dp[i][j]为真，说明是回文串并且它长度大于上一次记录的最大长度
                // 就记录此串的起始位置和长度
                if (dp[i][j] == true && j-i+1 > maxLen){
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }

        return s.substring(begin, begin + maxLen);
    }

    // 中心扩散法 时间复杂度:O(n^2)  空间复杂度 ： O(1)
    public String getLongestPalindrome2(String s){
        int maxLen = 1;
        int len = s.length();
        int begin = 0;
        char[] chars = s.toCharArray();
        if (s.length() < 2){ // 如果 s为单个字符 直接返回
            return s;
        }

        for (int i = 0; i < s.length() - 1; i++) {
            int oddLen = expandAroundCenter(chars, i, i);
            int evenLen = expandAroundCenter(chars, i, i+1);
            int l = Math.max(oddLen, evenLen);
            if (l > maxLen){
                maxLen = l;
                begin = i - (maxLen-1) / 2;
            }
        }

        return s.substring(begin,begin + maxLen);
    }

    // 中心扩散法取最长回文串长度
    public int expandAroundCenter(char[] chars, int left, int right){
        int L = left, R = right;
        // 当两个字符相同时，代表是回文串，再循环往外扩散
        while (L >= 0 && R < chars.length && chars[L] == chars[R]){
            L--;
            R++;
        }
        return R-L-1;
    }



    // main
    public static void main(String[] args) {
        LongestPalindrome lp = new LongestPalindrome();
        String result = lp.getLongestPalindrome2("bb");
        System.out.print(result);
    }
}
